home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-01-10 | 25.5 KB | 1,094 lines |
- Newsgroups: comp.sources.unix
- From: dws@cs.wisc.edu (DaviD W. Sanderson)
- Subject: v25i096: utmp - utility to repair broken /etc/utmp files
- Sender: sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: dws@cs.wisc.edu (DaviD W. Sanderson)
- Posting-Number: Volume 25, Issue 96
- Archive-Name: utmp
-
- I wrote this program to help me repair /etc/utmp files left for
- whatever reason with invalid entries. It works for the utmp file
- formats on System V, BSD, AIX3, and AIX 2 (though recently I haven't
- had access to an AIX 2 system to make sure it still works there). I
- designed the code to make it easy to add or remove fields for a new
- utmp format.
-
- dws@cs.wisc.edu (DaviD W. Sanderson)
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: README utmp.1 utmp.c Makefile
- # Wrapped by dws@skinner on Sat Dec 21 17:06:59 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(387 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XI wrote this program to help me repair /etc/utmp files left for
- Xwhatever reason with invalid entries. It works for the utmp file
- Xformats on System V, BSD, AIX3, and AIX 2 (though recently I haven't
- Xhad access to an AIX 2 system to make sure it still works there). I
- Xdesigned the code to make it easy to add or remove fields for a new
- Xutmp format.
- X
- XDaviD W. Sanderson (dws@cs.wisc.edu)
- END_OF_FILE
- if test 387 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'utmp.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'utmp.1'\"
- else
- echo shar: Extracting \"'utmp.1'\" \(1727 characters\)
- sed "s/^X//" >'utmp.1' <<'END_OF_FILE'
- X.\"-------
- X.\" $RCSfile: utmp.1,v $$Revision: 1.2 $$Date: 1991/12/21 23:03:43 $
- X.\"
- X.\" $Log: utmp.1,v $
- X.\" Revision 1.2 1991/12/21 23:03:43 dws
- X.\" Added caveats.
- X.\"
- X.\" Revision 1.1 1991/12/21 21:46:38 dws
- X.\" Initial revision
- X.\"
- X.\"-------
- X.TH UTMP 1
- X.SH NAME
- Xutmp \- translate between binary and textual utmp files
- X.SH SYNOPSIS
- X.B utmp
- X.RB [ \-v ]
- X.RI [ filename ]
- X.SH DESCRIPTION
- X.I utmp
- Xis useful for fixing a corrupted /etc/utmp file.
- XUse
- X.I utmp
- Xto obtain a printable representation of the file.
- XEdit it, and then use
- X.I utmp
- Xagain to translate it back into binary form.
- X.PP
- X.I utmp
- Xreads from the given file, or stdin if none is given (/etc/utmp
- Xif stdin is a tty), and writes to stdout.
- XIt detects automatically which transformation to apply.
- X.PP
- XThe flag
- X.B \-v
- Xindicates that times are to be printed in a
- Xhuman-comprehensible form.
- XNote that this output format is not
- Xcurrently inverted, so it is not useful for making repairs.
- X.PP
- XIf
- X.I utmp
- Xis working correctly then
- X.PP
- X.in +0.5i
- X$ utmp
- X.in
- X.PP
- Xand
- X.PP
- X.in +0.5i
- X$ utmp | utmp | utmp
- X.in
- X.PP
- Xshould produce the same output.
- XIdeally
- X.PP
- X.in +0.5i
- X$ utmp | utmp | cmp \- /etc/utmp
- X.in
- X.PP
- Xshould produce no output, but some systems don't fill the entire
- Xunused part of the character fields with NULs.
- X.SH CAVEATS
- XI encourage system administrators to install this command
- Xsomewhere besides /etc.
- X.PP
- XThere are probably /etc/utmp formats I do not yet accomodate.
- X.SH FILES
- X/etc/utmp
- X.br
- X/etc/wtmp
- X.SH "SEE ALSO"
- X.IR who (1),
- X(SysV)
- X.IR utmp (4),
- X(BSD)
- X.IR utmp (5)
- X.SH AUTHOR
- XDaviD W. Sanderson (dws\|@cs.wisc.edu)
- X.SH COPYRIGHT
- X\&
- X.br
- X.if n (C)
- X.if t \s+8\v'+2p'\fB\(co\fR\v'-2p'\s0
- X\s+2Copyright 1991 by DaviD W. Sanderson\s0
- X(but freely redistributable)
- END_OF_FILE
- if test 1727 -ne `wc -c <'utmp.1'`; then
- echo shar: \"'utmp.1'\" unpacked with wrong size!
- fi
- # end of 'utmp.1'
- fi
- if test -f 'utmp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'utmp.c'\"
- else
- echo shar: Extracting \"'utmp.c'\" \(19486 characters\)
- sed "s/^X//" >'utmp.c' <<'END_OF_FILE'
- X/*
- X * $RCSfile: utmp.c,v $$Revision: 1.2 $$Date: 1991/12/21 22:02:57 $
- X *
- X * utmp - translate between binary and textual utmp files.
- X *
- X * This is useful for fixing a corrupted /etc/utmp. Use utmp to obtain
- X * a printable representation of the file. Edit it, and then use
- X * utmp again to translate it back into binary form.
- X *
- X * usage: utmp [-v] [infile]
- X *
- X * utmp reads from the given file, or stdin if none is given (/etc/utmp
- X * if stdin is a tty), and writes to stdout. It detects which
- X * transformation it is to apply automatically.
- X *
- X * The flag -v indicates that times are to be printed in a
- X * human-comprehensible form. Note that this output format is not
- X * currently inverted, so it is not useful for making repairs.
- X */
- X/**
- X * If utmp is working correctly then
- X *
- X * $ utmp
- X * and
- X * $ utmp | utmp | utmp
- X *
- X * should produce the same output. Ideally
- X *
- X * $ utmp | utmp | cmp - /etc/utmp
- X *
- X * should produce no output, but some systems don't fill the entire
- X * unused part of the character fields with NULs.
- X */
- X/**
- X * The device used to detect what sort of struct utmp we have is
- X * to see whether USER_PROCESS (a value for ut_type) is defined by
- X * the include files. If it is, then struct utmp probably looks
- X * like this:
- X *
- X * struct utmp
- X * {
- X * char ut_user[8]; User login name
- X * char ut_id[4]; /etc/inittab id
- X * char ut_line[12]; device name (console, lnxx)
- X * short ut_pid; process id
- X * short ut_type; type of entry
- X * struct exit_status
- X * {
- X * short e_termination; Process termination status
- X * short e_exit; Process exit status
- X * } ut_exit; The exit status of a process
- X * marked as DEAD_PROCESS.
- X * time_t ut_time; time entry was made
- X * };
- X *
- X * AIX 3 systems have utmp entries like this:
- X *
- X * struct utmp
- X * {
- X * char ut_user[8]; User login name
- X * char ut_id[14]; /etc/inittab id
- X * char ut_line[12]; device name (console, lnxx)
- X * short ut_type; type of entry
- X * pid_t ut_pid; process id
- X * struct exit_status
- X * {
- X * short e_termination; Process termination status
- X * short e_exit; Process exit status
- X * } ut_exit; The exit status of a process
- X * marked as DEAD_PROCESS.
- X * time_t ut_time; time entry was made
- X * char ut_host[16]; host name
- X * };
- X *
- X * To use abbreviations of the symbolic ut_type names, compile with
- X * SHORT_TYPES defined.
- X *
- X * If USER_PROCESS is not defined, I assume an archaic struct utmp
- X * like this:
- X *
- X * struct utmp
- X * {
- X * char ut_line[8]; tty name
- X * char ut_name[8]; user id
- X * char ut_host[16]; host name, if remote
- X * long ut_time; time on
- X * };
- X *
- X * $Log: utmp.c,v $
- X * Revision 1.2 1991/12/21 22:02:57 dws
- X * Improved the comments.
- X *
- X * Revision 1.1 1991/12/21 21:44:04 dws
- X * Initial revision
- X *
- X */
- X
- X#include <sys/types.h>
- X#include <assert.h>
- X#include <ctype.h>
- X#include <time.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <utmp.h>
- X
- Xextern void exit();
- X
- X/*
- X * Configuration Section
- X *
- X * Configuration is done on a field-by-field basis, for the greatest
- X * flexibility (who knows what those vendors will think up next?).
- X *
- X * If the symbolic ut_type names are available, assume a SysV-like set
- X * of fields. Otherwise, assume BSD fields.
- X *
- X * On some systems, utmp has no ut_id field, and ut_id is #defined to
- X * ut_line.
- X *
- X * AIX3 systems have the ut_host field.
- X */
- X
- X#ifdef USER_PROCESS
- X# define HAVE_ut_user
- X# ifndef ut_id
- X# define HAVE_ut_id
- X# endif
- X# define HAVE_ut_line
- X# define HAVE_ut_pid
- X# define HAVE_ut_type
- X# define HAVE_ut_exit
- X# define HAVE_ut_time
- X# ifdef _AIX
- X# define HAVE_ut_host
- X# endif
- X#else
- X# define HAVE_ut_line
- X# define HAVE_ut_name
- X# define HAVE_ut_host
- X# define HAVE_ut_time
- X#endif
- X
- X#ifndef UTMP_FILE
- X#define UTMP_FILE "/etc/utmp"
- X#endif
- X
- X/*
- X * getopt() Section
- X *
- X * The usage() function uses write() instead of printf() so that
- X * programs using this template will not necessarily have to use stdio.
- X */
- X
- Xextern int write();
- X
- X/*
- X * swrite() - write() a "string variable" (char *)
- X */
- X
- X#define swrite(fd, s) (void) write((fd), (s), strlen(s))
- X
- X/*
- X * lwrite() - write() a "string literal" (char [])
- X */
- X
- X#define lwrite(fd, lit) (void) write((fd), (lit), sizeof(lit)-1)
- X
- X/*
- X * basename(s) - assumes the string does not end in '/'
- X *
- X * This used to be
- X *
- X * #define basename(s) (strrchr((s),'/') ? strrchr((s),'/')+1 : (s))
- X *
- X * but some systems don't have strrchr() and I didn't want to mess
- X * with switching between strrchr() and rindex().
- X */
- X
- Xstatic char *
- Xbasename(s)
- Xchar *s;
- X{
- X char *p;
- X
- X if (!s || !*s)
- X return s;
- X
- X for(p = s; *s; s++)
- X if(*s == '/')
- X p = s+1;
- X return p;
- X}
- X
- Xstatic char cmdopt[] = "v";
- Xstatic char cmdusg[] = " [-v] [filename]\n";
- X
- Xstatic int flag_v = 0;
- X
- Xstatic void
- Xusage(cmd)
- Xchar *cmd;
- X{
- X static char prefix[] = "usage: ";
- X char *p = cmd ? basename(cmd) : "a.out";
- X int fd = 2;
- X
- X lwrite(fd, prefix);
- X swrite(fd, p);
- X lwrite(fd, cmdusg);
- X}
- X
- X/*
- X * cmdline() - return the index of the first non-option argument
- X */
- Xstatic int
- Xcmdline(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern void exit();
- X extern char *optarg; /* points to the option argument */
- X extern int opterr; /* when 0, getopt is silent on errors */
- X extern int optind; /* argv[optind] is the next argument */
- X extern int optopt; /* current option letter */
- X
- X int errflag = 0; /* usage error flag */
- X int errcode = 1; /* usage error exit code */
- X int c;
- X
- X while((c = getopt(argc, argv, cmdopt)) != -1)
- X switch(c)
- X {
- X case 'v':
- X flag_v = 1;
- X break;
- X case '?':
- X errflag = 1;
- X if(optopt == '?')
- X errcode = 0;
- X break;
- X }
- X
- X if(errflag)
- X {
- X usage(argv[0]);
- X exit(errcode);
- X }
- X
- X return optind;
- X}
- X
- Xextern struct utmp *ud; /* dummy declaration so I can use sizeof() */
- X
- X/*
- X * LINSIZ is the number of bytes per line of the text representation
- X * of a utmp file (including the newline). The size of such a text
- X * file had better be a multiple of LINSIZ.
- X */
- Xstatic int LINSIZ = 1 /* 1 for the newline */
- X
- X#ifdef HAVE_ut_user
- X# define nut_user (sizeof(ud->ut_user)/sizeof(ud->ut_user[0]))
- X+ 1+nut_user
- X#endif
- X
- X#ifdef HAVE_ut_id
- X# define nut_id (sizeof(ud->ut_id )/sizeof(ud->ut_id [0]))
- X+ 1+nut_id
- X#endif
- X
- X#ifdef HAVE_ut_line
- X# define nut_line (sizeof(ud->ut_line)/sizeof(ud->ut_line[0]))
- X+ 1+nut_line
- X#endif
- X
- X#ifdef HAVE_ut_pid
- X# define nut_pid 5
- X+ 1+nut_pid
- X#endif
- X
- X#ifdef HAVE_ut_type
- X# if defined(SHORT_TYPES)
- X# define nut_type 4
- X# else
- X# define nut_type 10
- X# endif
- X+ 1+nut_type
- X#endif
- X
- X#ifdef HAVE_ut_exit
- X# define nut_exit 17
- X+ 1+nut_exit
- X#endif
- X
- X#ifdef HAVE_ut_name
- X# define nut_name (sizeof(ud->ut_name)/sizeof(ud->ut_name[0]))
- X+ 1+nut_name
- X#endif
- X
- X#ifdef HAVE_ut_host
- X# define nut_host (sizeof(ud->ut_host)/sizeof(ud->ut_host[0]))
- X+ 1+nut_host
- X#endif
- X
- X#ifdef HAVE_ut_time
- X# define nut_time 10
- X+ nut_time
- X#endif
- X; /* End of LINSIZ initialization */
- X
- X/*
- X * VIS_SPC - visible printing character used to represent a space
- X *
- X * VIS_TAB - visible printing character used to represent a tab
- X *
- X * VIS_NUL - visible printing character used to represent a NUL
- X *
- X * The way the i/o translation works, the representation of each field
- X * must have no white space. These visible characters are used to
- X * represent the invisible characters. (Note the inverse mapping
- X * will be wrong if the utmp file actually contains any of these
- X * characters.)
- X *
- X * These characters are not just an artifact of using scanf() to read in
- X * each field. I used visible characters so that the extents and
- X * boundaries of the array fields would be clear.
- X *
- X * ENVIS() and DEVIS() perform the translations on the given character
- X * array.
- X */
- X
- X#define VIS_NUL '_'
- X#define VIS_TAB '^'
- X#define VIS_SPC '~'
- X#define CHR_NUL 0
- X#define CHR_TAB 9
- X#define CHR_SPC 32
- X
- X#define ENVIS(str) \
- X { \
- X int i; \
- X \
- X for(i=0; i<sizeof(str)-1; i++) \
- X switch((str)[i]) \
- X { \
- X case CHR_NUL: (str)[i]=VIS_NUL; break; \
- X case CHR_TAB: (str)[i]=VIS_TAB; break; \
- X case CHR_SPC: (str)[i]=VIS_SPC; break; \
- X } \
- X }
- X
- X#define DEVIS(str) \
- X { \
- X int i; \
- X \
- X for(i=0; i<sizeof(str)-1; i++) \
- X switch((str)[i]) \
- X { \
- X case VIS_NUL: (str)[i]=CHR_NUL; break; \
- X case VIS_TAB: (str)[i]=CHR_TAB; break; \
- X case VIS_SPC: (str)[i]=CHR_SPC; break; \
- X } \
- X }
- X
- X/*
- X * These macros convert the given character args to an integer. (I
- X * assume ints are at least 4 bytes long...)
- X *
- X * They serve as hash functions, with the useful property that they can
- X * be used in case labels when given constants as arguments.
- X */
- X
- X#define char1int(a) ((unsigned)(a))
- X#define char2int(a,b) ((char1int(a) <<8) + (char1int(b)))
- X#define char3int(a,b,c) ((char2int(a,b) <<8) + (char1int(c)))
- X#define char4int(a,b,c,d) ((char3int(a,b,c)<<8) + (char1int(d)))
- X
- X#ifdef HAVE_ut_time
- X/*
- X * cvt_pb_pm() - convert Abbreviated Month name (cftime(3C) field
- X * descriptor %b) to Month Number (01 - 12) (cftime(3C) field
- X * descriptor %m).
- X */
- X
- Xchar *
- Xcvt_pb_pm(pb)
- X char *pb;
- X{
- X char *pm = "??";
- X
- X switch(char3int(pb[0],pb[1],pb[2]))
- X {
- X case char3int('J','a','n'): pm = "01"; break;
- X case char3int('F','e','b'): pm = "02"; break;
- X case char3int('M','a','r'): pm = "03"; break;
- X case char3int('A','p','r'): pm = "04"; break;
- X case char3int('M','a','y'): pm = "05"; break;
- X case char3int('J','u','n'): pm = "06"; break;
- X case char3int('J','u','l'): pm = "07"; break;
- X case char3int('A','u','g'): pm = "08"; break;
- X case char3int('S','e','p'): pm = "09"; break;
- X case char3int('O','c','t'): pm = "10"; break;
- X case char3int('N','o','v'): pm = "11"; break;
- X case char3int('D','e','c'): pm = "12"; break;
- X }
- X return (pm);
- X}
- X
- X/*
- X * utgets_time() - set the ut_time field from the given file
- X */
- Xutgets_time(f, ut)
- X FILE *f;
- X struct utmp *ut; /* utmp structure to print */
- X{
- X (void)fscanf(f,"%ld", &ut->ut_time);
- X}
- X
- X/*
- X * utputs_time() - print the ut_time field to the given file
- X *
- X * Note that if flag_v is set the output will not be invertible by
- X * utgets().
- X */
- Xutputs_time(f, ut)
- X FILE *f;
- X struct utmp *ut; /* utmp structure to print */
- X{
- X char time[BUFSIZ];
- X int ntime;
- X char *ptime;
- X
- X if(!flag_v)
- X {
- X (void)fprintf(f,"%*ld", nut_time, ut->ut_time);
- X return;
- X }
- X
- X /* make sure time[] starts out null */
- X for(ptime = time; ptime < time + sizeof time; ptime++)
- X *ptime = '\0';
- X#if 0
- X (void)memset(time,0,sizeof(time)/sizeof(time[0]));
- X#endif
- X
- X /*
- X * Format the time field in a compact, sortable form
- X *
- X * ctime returns a pointer to a 26-character string in the
- X * following form:
- X *
- X * Sun Sep 16 01:03:52 1973\n\0
- X * 012345678901234567890123 4 5
- X *
- X * I want the time displayed as
- X *
- X * yy/mm/dd hh:mm:ss
- X * 01234567890123456
- X *
- X * Since cftime is not available everywhere, I will construct
- X * the time myself using the result of ctime().
- X */
- X#if 0
- X /* This is how simple it is with cftime() */
- X ntime = cftime(time, "%y/%m/%d %T", &(ut->ut_time));
- X#endif
- X
- X ntime = 0;
- X ptime = ctime(&(ut->ut_time));
- X
- X strncat(time, ptime + 22, 2); ntime += 2; /* yy */
- X time[ntime++] = '/';
- X strncat(time, cvt_pb_pm(ptime + 4), 2); ntime += 2; /* mm */
- X time[ntime++] = '/';
- X
- X strncat(time, ptime + 8, 2); ntime += 2; /* dd */
- X if(time[ntime-2] == ' ') /* add leading '0' */
- X time[ntime-2] = '0';
- X
- X time[ntime++] = ' ';
- X strncat(time, ptime + 11, 8); ntime += 8; /* hh:mm:ss */
- X
- X time[ntime] = '\0'; /* just to be paranoid */
- X
- X assert(ntime < (sizeof(time)/sizeof(time[0])) - 1);
- X
- X (void)fprintf(f, "%*s", ntime, time);
- X}
- X#endif
- X
- X/*
- X * utgets() - translate a text line from the given file into a struct
- X * utmp
- X */
- Xstruct utmp *
- Xutgets(f)
- X FILE *f;
- X{
- X static struct utmp utb;
- X static struct utmp *ut = &utb;
- X
- X if (!f || feof(f))
- X return (struct utmp *) 0;
- X
- X /*
- X * Read in the fields
- X */
- X#ifdef HAVE_ut_user
- X {
- X char user[nut_user + 1];
- X
- X (void) fscanf(f, "%s", user);
- X user[nut_user] = '\0';
- X DEVIS(user);
- X (void) strncpy(ut->ut_user, user, nut_user);
- X }
- X#endif
- X#ifdef HAVE_ut_id
- X {
- X char id[nut_id + 1];
- X
- X (void) fscanf(f, "%s", id);
- X id[nut_id] = '\0';
- X DEVIS(id);
- X (void) strncpy(ut->ut_id, id, nut_id);
- X }
- X#endif
- X#ifdef HAVE_ut_line
- X {
- X char line[nut_line + 1];
- X
- X (void) fscanf(f, "%s", line);
- X line[nut_line] = '\0';
- X DEVIS(line);
- X (void) strncpy(ut->ut_line, line, nut_line);
- X }
- X#endif
- X#ifdef HAVE_ut_pid
- X {
- X long pid;
- X /* (void)fscanf(f,"%hd", &ut->ut_pid); */
- X
- X (void)fscanf(f,"%ld", &pid);
- X ut->ut_pid = pid;
- X }
- X#endif
- X#ifdef HAVE_ut_type
- X {
- X char type[20];
- X short btype = 999;
- X
- X (void)fscanf(f,"%s", type);
- X /* decode the type */
- X# if defined(SHORT_TYPES)
- X switch(char4int(type[0],type[1],type[2],type[3]))
- X {
- X case char4int('N','U','L','L'): btype = EMPTY; break;
- X case char4int('R','L','V','L'): btype = RUN_LVL; break;
- X case char4int('B','O','O','T'): btype = BOOT_TIME; break;
- X case char4int('O','L','D','T'): btype = OLD_TIME; break;
- X case char4int('N','E','W','T'): btype = NEW_TIME; break;
- X case char4int('I','N','I','P'): btype = INIT_PROCESS; break;
- X case char4int('L','O','G','P'): btype = LOGIN_PROCESS; break;
- X case char4int('U','S','R','P'): btype = USER_PROCESS; break;
- X case char4int('D','E','D','P'): btype = DEAD_PROCESS; break;
- X case char4int('A','C','C','T'): btype = ACCOUNTING; break;
- X default:
- X fprintf(stderr, "bad type: %s\n", type);
- X }
- X# else
- X switch(char4int(type[0],type[1],type[2],type[3]))
- X {
- X case char4int('E','M','P','T'): btype = EMPTY; break;
- X case char4int('R','U','N','_'): btype = RUN_LVL; break;
- X case char4int('B','O','O','T'): btype = BOOT_TIME; break;
- X case char4int('O','L','D','_'): btype = OLD_TIME; break;
- X case char4int('N','E','W','_'): btype = NEW_TIME; break;
- X case char4int('I','N','I','T'): btype = INIT_PROCESS; break;
- X case char4int('L','O','G','I'): btype = LOGIN_PROCESS; break;
- X case char4int('U','S','E','R'): btype = USER_PROCESS; break;
- X case char4int('D','E','A','D'): btype = DEAD_PROCESS; break;
- X case char4int('A','C','C','O'): btype = ACCOUNTING; break;
- X default:
- X fprintf(stderr, "bad type: %s\n", type);
- X }
- X# endif
- X ut->ut_type = btype;
- X }
- X#endif
- X#ifdef HAVE_ut_exit
- X (void)fscanf(f," term=%hd", &ut->ut_exit.e_termination);
- X (void)fscanf(f," exit=%hd", &ut->ut_exit.e_exit);
- X#endif
- X#ifdef HAVE_ut_name
- X {
- X char name[nut_name + 1];
- X
- X (void) fscanf(f, "%s", name);
- X name[nut_name] = '\0';
- X DEVIS(name);
- X (void) strncpy(ut->ut_name, name, nut_name);
- X }
- X#endif
- X#ifdef HAVE_ut_host
- X {
- X char host[nut_host + 1];
- X
- X (void) fscanf(f, "%s", host);
- X host[nut_host] = '\0';
- X DEVIS(host);
- X (void) strncpy(ut->ut_host, host, nut_host);
- X }
- X#endif
- X#ifdef HAVE_ut_time
- X utgets_time(f, ut);
- X#endif
- X
- X (void) fscanf(f, "\n");
- X
- X return ut;
- X}
- X
- X/*
- X * utputs() - translate from a struct utmp to a text line in the given
- X * file
- X */
- Xutputs(f, ut)
- X FILE *f;
- X struct utmp *ut; /* utmp structure to print */
- X{
- X if (!ut || !f)
- X return 0;
- X
- X /*
- X * Print out the fields
- X */
- X
- X#ifdef HAVE_ut_user
- X {
- X char user[nut_user + 1];
- X
- X (void) strncpy(user, ut->ut_user, nut_user);
- X user[nut_user] = '\0';
- X ENVIS(user);
- X (void) fprintf(f, "%*s ", nut_user, user);
- X }
- X#endif
- X#ifdef HAVE_ut_id
- X {
- X char id[nut_id + 1];
- X
- X (void) strncpy(id, ut->ut_id, nut_id);
- X id[nut_id] = '\0';
- X ENVIS(id);
- X (void) fprintf(f, "%*s ", nut_id, id);
- X }
- X#endif
- X#ifdef HAVE_ut_line
- X {
- X char line[nut_line + 1];
- X
- X (void) strncpy(line, ut->ut_line, nut_line);
- X line[nut_line] = '\0';
- X ENVIS(line);
- X (void) fprintf(f, "%*s ", nut_line, line);
- X }
- X#endif
- X#ifdef HAVE_ut_pid
- X (void)fprintf(f,"%*d ", nut_pid, ut->ut_pid);
- X#endif
- X#ifdef HAVE_ut_type
- X {
- X char *type;
- X
- X# if defined(SHORT_TYPES)
- X switch(ut->ut_type)
- X {
- X case EMPTY: type = "NULL"; break;
- X case RUN_LVL: type = "RLVL"; break;
- X case BOOT_TIME: type = "BOOT"; break;
- X case OLD_TIME: type = "OLDT"; break;
- X case NEW_TIME: type = "NEWT"; break;
- X case INIT_PROCESS: type = "INIP"; break;
- X case LOGIN_PROCESS: type = "LOGP"; break;
- X case USER_PROCESS: type = "USRP"; break;
- X case DEAD_PROCESS: type = "DEDP"; break;
- X case ACCOUNTING: type = "ACCT"; break;
- X default: type = "unk!"; break;
- X }
- X (void)fprintf(f,"%*s ", nut_type, type); /* 5 bytes */
- X# else
- X switch(ut->ut_type)
- X {
- X case EMPTY: type = "EMPTY"; break;
- X case RUN_LVL: type = "RUN_LVL"; break;
- X case BOOT_TIME: type = "BOOT_TIME"; break;
- X case OLD_TIME: type = "OLD_TIME"; break;
- X case NEW_TIME: type = "NEW_TIME"; break;
- X case INIT_PROCESS: type = "INIT_PROC"; break;
- X case LOGIN_PROCESS: type = "LOGIN_PROC"; break;
- X case USER_PROCESS: type = "USER_PROC"; break;
- X case DEAD_PROCESS: type = "DEAD_PROC"; break;
- X case ACCOUNTING: type = "ACCOUNTING"; break;
- X default: type = "unknown!"; break;
- X }
- X (void)fprintf(f,"%-*s ", nut_type, type); /* 11 bytes */
- X# endif
- X }
- X#endif
- X#ifdef HAVE_ut_exit
- X (void)fprintf(f,"term=%*d exit=%*d ",
- X 3,
- X ut->ut_exit.e_termination,
- X 3,
- X ut->ut_exit.e_exit
- X );
- X#endif
- X#ifdef HAVE_ut_name
- X {
- X char name[nut_name + 1];
- X
- X (void) strncpy(name, ut->ut_name, nut_name);
- X name[nut_name] = '\0';
- X ENVIS(name);
- X (void) fprintf(f, "%*s ", nut_name, name);
- X }
- X#endif
- X#ifdef HAVE_ut_host
- X {
- X char host[nut_host + 1];
- X
- X (void) strncpy(host, ut->ut_host, nut_host);
- X host[nut_host] = '\0';
- X ENVIS(host);
- X (void) fprintf(f, "%*s ", nut_host, host);
- X }
- X#endif
- X#ifdef HAVE_ut_time
- X utputs_time(f, ut);
- X#endif
- X
- X (void) putc('\n', f);
- X
- X return 1;
- X}
- X
- X/*
- X * utget() - read a struct utmp from the given file
- X */
- Xstruct utmp *
- Xutget(f)
- X FILE *f;
- X{
- X static struct utmp utb;
- X static struct utmp *ut = &utb;
- X
- X if (fread((char *) ut, sizeof(*ut), 1, f) != 1)
- X return (struct utmp *) 0;
- X
- X return ut;
- X}
- X
- X/*
- X * utput() - write a struct utmp to the given file
- X */
- Xutput(f, ut)
- X FILE *f;
- X struct utmp *ut;
- X{
- X if (!ut || !f)
- X return 0;
- X
- X return fwrite((char *) ut, sizeof(*ut), 1, f);
- X}
- X
- X/*
- X * docopy() - copy from i to o, translating as appropriate
- X */
- Xdocopy(i, o)
- X FILE *i;
- X FILE *o;
- X{
- X FILE *tmp = tmpfile();
- X int ilen = 0; /* size of i file */
- X int binary = 0; /* 1 if i file is binary */
- X int c;
- X
- X /*
- X * The textual representation may contain only printing
- X * characters - only the visible characters and space.
- X *
- X * If there is any character which is not ascii or is not
- X * printable, then treat the file as binary.
- X */
- X
- X while ((c = getc(i)) != EOF)
- X {
- X ilen++;
- X
- X if (!isascii(c) || !(isprint(c) || c == '\n'))
- X {
- X binary = 1;
- X }
- X
- X (void) putc(c, tmp);
- X }
- X if(ilen == 0)
- X return;
- X
- X rewind(tmp);
- X
- X if (binary)
- X {
- X#if 0
- X (void) fprintf(stderr, "Input is Binary\n");
- X#endif
- X if (ilen % sizeof(struct utmp))
- X {
- X (void) fprintf(stderr, "Binary wrong size!\n");
- X }
- X while (utputs(o, utget(tmp)))
- X continue;
- X }
- X else
- X {
- X#if 0
- X (void) fprintf(stderr, "Input is Text\n");
- X#endif
- X if (ilen % LINSIZ)
- X {
- X (void) fprintf(stderr, "Text wrong size!\n");
- X }
- X while (utput(o, utgets(tmp)))
- X continue;
- X }
- X}
- X
- Xmain(ac, av)
- X int ac;
- X char **av;
- X{
- X FILE *in = stdin;
- X FILE *out = stdout;
- X int optc = cmdline(ac, av);
- X
- X ac -= optc;
- X av += optc;
- X
- X switch (ac)
- X {
- X#if 0
- X case 2:
- X if ((out = fopen(av[1], "w")) == (FILE *) 0)
- X {
- X exit(1);
- X }
- X /* PASSTHROUGH */
- X#endif
- X case 1:
- X if ((in = fopen(av[0], "r")) == (FILE *) 0)
- X {
- X exit(1);
- X }
- X break;
- X case 0:
- X if (isatty(0))
- X {
- X if ((in = fopen(UTMP_FILE, "r")) == (FILE *) 0)
- X {
- X exit(1);
- X }
- X }
- X break;
- X default:
- X exit(1);
- X }
- X
- X docopy(in, out);
- X
- X return 0;
- X}
- END_OF_FILE
- if test 19486 -ne `wc -c <'utmp.c'`; then
- echo shar: \"'utmp.c'\" unpacked with wrong size!
- fi
- # end of 'utmp.c'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(866 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X#-------
- X# Installation parameters
- X#-------
- XBINDIR = $(root)/pub/bin/$(ht)
- XBINMOD = 500
- XBINOWN = dws
- XBINGRP = dws
- XMANDIR = $(root)/pub/man/man1
- XMANMOD = 400
- XMANOWN = dws
- XMANGRP = dws
- X
- XLINKER = $(CC)
- XLDFLAGS =
- XSHAR = shar
- X
- XPROG = utmp
- XPLUG = README
- XPAGE = utmp.1
- XTEXT = Makefile
- XHDRS =
- XSRCS = utmp.c
- XOBJS = utmp.o
- X
- Xall: $(PROG)
- X
- X$(PROG): $(OBJS)
- X $(LINKER) $(LDFLAGS) $(OBJS) -o $(PROG)
- X
- Xclean:; rm -f $(OBJS)
- X
- Xclobber: clean
- X rm -f $(PROG) $(PROG).shar
- X
- Xinstall: $(PROG) $(PAGE)
- X install -m $(BINMOD) -o $(BINOWN) -g $(BINGRP) -s $(PROG) $(BINDIR)
- X install -m $(MANMOD) -o $(MANOWN) -g $(MANGRP) -c $(PAGE) $(MANDIR)
- X
- Xuninstall:; rm -f $(BINDIR)/$(PROG)
- X rm -f $(MANDIR)/$(PAGE)
- X
- Xshar:; $(SHAR) $(PLUG) $(PAGE) $(HDRS) $(SRCS) $(TEXT) > $(PROG).shar
- END_OF_FILE
- if test 866 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- echo shar: End of shell archive.
- exit 0
-